package wxb.avalon.core.websocket;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Maps;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import wxb.avalon.core.bean.ApplicationContextRegister;
import wxb.avalon.core.bean.Result;
import wxb.avalon.core.entity.dto.RoomPlayerDto;
import wxb.avalon.core.entity.dto.WsParam;
import wxb.avalon.core.service.IRoomService;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/room/{roomNo}/{playerId}")
@Component
public class RoomServer {
    //concurrent包的线程安全Set，用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    private static ConcurrentHashMap<Session, Object> locks = new ConcurrentHashMap<>();

    private IRoomService roomService = null;

    //发送消息
    public void sendMessage(Session session, String message){
        locks.computeIfAbsent(session, k->{
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        });
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "roomNo") String roomNo,
                       @PathParam(value = "playerId") Integer playerId){
        if (null == roomService){
            //websocket 使用service 层
            ApplicationContext act = ApplicationContextRegister.getApplicationContext();
            roomService = act.getBean(IRoomService.class);
        }
        sessionPools.put(roomNo+"-"+playerId, session);
        System.out.println(roomNo+"-"+playerId + "加入webSocket");
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "roomNo") String roomNo,
                        @PathParam(value = "playerId") Integer playerId){
        sessionPools.remove(roomNo+"-"+playerId);
        List<RoomPlayerDto> list = roomService.quit(roomNo, playerId);
        if(!list.isEmpty()){
            getPlayersMap(roomNo);
        }
        System.out.println(roomNo+"-"+playerId + "断开webSocket连接！");
    }

    //收到客户端信息
    @OnMessage
    public void onMessage(String message) throws IOException{
        System.out.println(message);
        WsParam wsParam = JSONUtil.toBean(message, WsParam.class);
        switch (wsParam.getAction()){
            case "join"://加入房间
                JSONObject jsonObject = JSONUtil.parseObj(wsParam.getParam());
                String roomNo = jsonObject.getStr("roomNo");
                Integer playerId = jsonObject.getInt("playerId");
                joinMap(roomNo, playerId);
                break;
            case "createGame"://房主开始游戏
                jsonObject = JSONUtil.parseObj(wsParam.getParam());
                roomNo = jsonObject.getStr("roomNo");
                playerId = jsonObject.getInt("playerId");
                roomService.createGame(roomNo, playerId);
                startMap(roomNo);
                break;
            default:
        }

    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable){
        System.out.println("发生错误");
        throwable.printStackTrace();
    }


    private void broadCast(String roomNo, String msg){
        //这是广播
        sessionPools.keySet().forEach(e->{
            if (e.contains(roomNo+"-")){
                sendMessage(sessionPools.get(e), msg);
            }
        });
    }

    private void joinMap(String roomNo, Integer playerId){
        if (StringUtils.isNotBlank(roomNo) && null != playerId){
            Result<List<RoomPlayerDto>> result = roomService.join(roomNo, playerId);
            Map<String, Object> map = Maps.newLinkedHashMap();
            map.put("result", result);
            map.put("action", "join");
            broadCast(roomNo, JSONUtil.toJsonStr(map));
        }
    }

    private void getPlayersMap(String roomNo){
        Result<List<RoomPlayerDto>> result = new Result<>();
        List<RoomPlayerDto> list = roomService.getRoomPlayers(roomNo);
        result.ok(list);
        Map<String, Object> map = Maps.newLinkedHashMap();
        map.put("result", result);
        map.put("action", "join");
        broadCast(roomNo, JSONUtil.toJsonStr(map));
    }

    private void startMap(String roomNo){
        if (StringUtils.isNotBlank(roomNo)){
            Map<String, Object> map = Maps.newLinkedHashMap();
            map.put("result", roomNo);
            map.put("action", "start");
            broadCast(roomNo, JSONUtil.toJsonStr(map));
        }
    }

}